← ALL ARTICLES
渲染架构3 MIN READ

Forward Rendering与Forward+

全库目录221
本文目录6

材质着色时逐盏灯计算很直接,灯一多,每个片元遍历的无关光源也变多。Forward+把筛灯提前,材质仍在前向阶段计算。先检查列表保守性和资源可见性,再看提交、像素和列表构建的总成本,才能判断这一步是否改善整帧。

Forward Rendering

Forward 在绘制物体时直接计算光照并输出最终颜色。

简化流程:

text
Object → Vertex Shader → Rasterization → Material + Lights → Color

优点:

  • 流程直接;
  • 透明和自定义材质容易接入;
  • MSAA 相对自然;
  • 中间缓冲少,适合带宽敏感平台。

问题是要先决定每个物体受哪些灯影响。传统 Multi-pass Forward 可能对额外灯重复绘制物体;Single-pass Forward 会把灯列表传给着色器,但列表长度和分支受限。

不能简单说 Forward 的复杂度是 N2N^2。实际成本取决于可见对象、每个对象重叠灯数、屏幕覆盖、Pass 和剔除策略。

Forward+

Forward+ 保留 Forward 材质阶段,但先用 Tiled/Clustered Culling 建立灯列表。像素着色器只遍历当前区域的灯。

它结合了:

  • Forward 对透明、MSAA 和复杂材质的适应;
  • 屏幕分区对大量灯的筛选能力。

代价是需要构建灯列表,且不透明和透明阶段可能使用不同列表或深度信息。

本页读取的区域索引来自 Tiled与Clustered光源剔除。例如同一屏幕块里近处墙面与远处透明玻璃深度相差很大,只用不透明深度的最小最大值建表,会把玻璃附近的灯提前剔掉。透明阶段可使用覆盖完整视锥深度的簇表,或维护独立列表;选择改变的是候选集合,不改变材质 BRDF。

局部灯列表着色

以下为 HLSL 函数轮廓。输入片元位置、法线和对应区域索引,区域表记录灯索引缓冲的起点和数量。真实 BRDF、阴影和距离衰减由 EvaluateLight 提供。

hlsl
float3 ShadeLocalLights(float3 positionWS, float3 normalWS, uint region)
{
    uint2 range = LightRanges[region];
    float3 lighting = 0.0;
    for (uint localIndex = 0; localIndex < range.y; ++localIndex)
    {
        uint lightIndex = LightIndices[range.x + localIndex];
        lighting += EvaluateLight(Lights[lightIndex], positionWS, normalWS);
    }
    return lighting;
}

例如区域表为(5,2),该区域只读取索引缓冲第5、6项,假设其值为3、9,就分别评价灯3和灯9。第5项是索引地址,不是灯ID。把range.x误当lightIndex会评价灯5并漏掉灯3;逐项显示索引链可以区分建表与消费错误。

读取前要保证构建列表的计算写入对图形着色可见。区域索引、数组容量与灯数据寿命必须匹配。用遍历全部光源的参考着色验证局部列表,结果差异提示漏灯、范围或阴影数据错误。

验证方法

  • 记录材质绘制与灯光循环,确认列表只影响候选灯。
  • 增加灯光和透明对象,对比普通前向与 Forward+ 的整帧耗时。
  • 检查溢出列表、深度范围及透明路径使用的光源集合。

相关主题

示例与验证范围:代码按文中前提解释机制,完整类型、资源和项目状态需由接入工程补齐。完整目标引擎运行与GPU性能为UNVERIFIED;正文给出的机制与实际实验范围分别记录。

参考资料

  • AMD:ForwardPlus11:官方样例 README:计算着色器构造局部灯列表、前向像素着色消费;本文未构建该旧版 D3D11 样例。